#ifndef LOGICENGINE_HPP
#define LOGICENGINE_HPP

#include <Box2D.h>
#include <iostream>
#include <vector>

#include "ControlManager.hpp"
#include "Element.hpp"
#include "Scene.hpp"
#include "SpotlightElement.hpp"
#include "SwitchElement.hpp"

using namespace std;

class LogicEngine {
private:
    class ContactListener : public b2ContactListener {
    private:
        void beginContactWithExit(ExitElement* exitElement, Element* element);
        void beginContactWithFlash(FlashElement* flashElement, Element* element);
        void beginContactWithSwitch(SwitchElement* switchElement, Element* element);
        void endContactWithFlash(FlashElement* flashElement, Element* element);
        void endContactWithSwitch(SwitchElement* switchElement, Element* element);
        void preSolveWithSpotlight(b2Contact* contact, LightElement* spotlight, Element* element);

    public:
        bool exitTouched;
        int numberOfFootCollisions;

        ContactListener();

        void BeginContact(b2Contact* contact);
        void EndContact(b2Contact* contact);
        void PreSolve(b2Contact* contact, const b2Manifold* oldManifold);
    };

    class RayCastCallback : public b2RayCastCallback {
    public:
        int numberOfCollisions;

        RayCastCallback();

        float ReportFixture(b2Fixture* fixture, const b2Vec2 &point, const b2Vec2 &normal, float fraction);
    };

    static const float ATTRACTION_VELOCITY;
    static const float GRAB_RADIUS;

    bool allowInput;
    ContactListener* contactListener;
    ControlManager* controlManager;
    float elapsedTimeFromExitTouching;
    float firstTime;
    float lastHeroY;
    float lastTime;

    void manageHero(Scene* scene);
    //void movePlatform(MoveablePlatformElement* moveablePlatform);
    static void setFriction(Element* element, float friction);
    static void setRestitution(Element* element, float restitution);

public:
    LogicEngine(ControlManager* controlManager);

    void end();
    void init(Scene* scene, float elapsedTime);
    bool isSceneCompleted();
    void render(Scene* scene, float elapsedTime);
    void setLastTime(float time);
};

#endif
